package org.mil.logic;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.mil.util.FileSystemUtil;

/**
 * wiki式文件命名的智能分析器
 * @author HZK
 *
 */
public class WikiNameInfo {
	private String EnglishName="";	//英文名
	private String AsianName="";	//象形文字名称，主要是中文名，也可能是日文，朝鲜文
	private String year="";		//原作品发行年代 ,如1997,2010
	private String source="";		//压制片源，如bd,bdrip,d9,dd51,bluray,remux,R5,dvdscr,dvdrip
	private String version="";		//片源版本，如DC,Extended,CC,IMAX,2D,3D
	private String producer="";	//压片作者或其组织，如TLF,CHD,Silu,Wiki,YYeTs,XTM,NORM,
	private String standard="";	//采用的较知名的压片标准，如a720,miniSD,halfcd,iNT,480p
	
	private String fileNameN;   //原文件名，所有解析结果的信息来源
	private String fileNameL;	//原文件名的小写形式
	
	private static Map<String,String> mSources=new LinkedHashMap<String, String>();
	private static Map<String,String> mVersions=new LinkedHashMap<String, String>();		
	private static Map<String,String> mStandards=new LinkedHashMap<String, String>();
	private static Map<String,String> mProducers=new LinkedHashMap<String, String>();
	private static boolean isDataLoaded=false;
	
	private int pYear;	//年代出现位置
	private int pEnName;	//英文名称出现位置
	
	
	public static WikiNameInfo newInstance(String _fileName){
		WikiNameInfo info=new WikiNameInfo();
		if (!isDataLoaded) loadData();
		info.parse(_fileName);
		return info;
		
		
	}
	public void parse(String _fileName){
		if (_fileName==null) return;
		//fileNameL取小写值，便于之后的大小写不敏感的关键字检索
		fileNameN=_fileName;
		fileNameL=fileNameN.toLowerCase();
		//先查找年代,年代位数为4
		pYear=findYear();
		int nYear=4;
		//若找不到年代，则找片源source的位置来代替
		if (pYear<0) {
			for (String key:mSources.keySet()) 
				if (fileNameL.indexOf(key)>=0) {
					pYear=fileNameL.indexOf(key);
					nYear=0;
					break;
				}
			//pYear<0表示仍然无法找到，格式严重不符以致无法解析，则退出
			if (pYear<0) return;			
		}
		//再查找英文名称
		pEnName=findEnName();
		//英文名称前就是亚洲名称
		if (pEnName<0) return;
		if (pEnName>0)
			AsianName=fileNameN.substring(0,pEnName-1);
		if (pEnName<pYear-1 && pEnName>=0)
		EnglishName=fileNameN.substring(pEnName,pYear-1);
		
		//去亚洲名除去方括号	 
		AsianName=trimBrackets(AsianName);
		year=fileNameL.substring(pYear, pYear+nYear);
		//剩下的字段
		String other=fileNameL.substring(pYear+nYear);
		//查找关键字,并赋值所有重要字段
		
		for (String key:mSources.keySet()) 
			if (other.indexOf(key)>=0) {
				source=mSources.get(key);
				break;
			}
		for (String key:mVersions.keySet())
			if (fileNameL.indexOf(key)>=0) {
				version=mVersions.get(key);
				break;
			}
		for (String key:mStandards.keySet())
			if (other.indexOf(key)>=0) {
				standard=mStandards.get(key);
				break;
			}
		boolean findInMap=false;
		for (String key:mProducers.keySet())
			if (other.indexOf(key)>=0) {
				producer=mProducers.get(key);
				findInMap=true;
				break;
			}
		/*如果未在预存数据地图中找到组织名producer，尝试一下自行截取
		算法：最后一个'-'后接的不含小圆点的字符串
		原则上，组织名长度在[1,12]之间,且不带小圆点
		*/int p_max=12,p_min=1;//int dot='.';
		
		if(!findInMap){
			int x=fileNameN.lastIndexOf('-');		
			if(x>0 && x>fileNameN.length()-p_max) 
			producer=fileNameN.substring(x+1).split("\\.")[0];			
			
			if (producer.length()<p_min || producer.length()>p_max) producer="";
			
				
		}
		
	}
	
	/**
	 * 查找年代出现的位置
	 *  算法：年代是字串中的最后一个连续4位数字子串就是“年代”
	 *  
	 * @return 位置，若找不到返回-1
	 */
	private int findYear(){
		int x=fileNameL.length();
		while (--x>=0)
			if (isNum(x) && isNum(x-1) && isNum(x-2)&& isNum(x-3)) return x-3;
		
		return -1;
	}
	/**
	 * 查找英文名称出现的位置
	 * 算法：以小圆点为分隔符陈列出所有“单词”， 然后返回第一个出现的“纯英文单词”
	 * @return
	 */
	private int findEnName(){
		//手动实现String.split()方法
		String[] words=new String[30];	//split后的单词列表
		int[] wordsx=new int[30];		//单词列表words的相应的首字母位移
		String s=fileNameL.substring(0,pYear);	//s为所要split的原字符串
		char dot='.';				//split的分隔符
		int nwords;					//单词列表words的大小
		int x=-1,y,k=0;
		while (x<s.length()){
			y=s.indexOf(dot,x+1);
			if (y<x || y<0)  {
				words[k]=s.substring(x+1);
				wordsx[k++]=x+1;
				break;
			}
			words[k]=s.substring(x+1,y);
			wordsx[k++]=x+1;
			x=y;
		}
		nwords=k;		
		

		for (k=0;k<nwords;k++)
			if (isPureEn(words[k])) return wordsx[k];
		return -1;
	}
	/**
	 * 判断文件名fileName的指定字符是否为数字,
	 * 此函数包含了非法边界的检查，若字符位置非法，返回false
	 * @param pos 此字符位置
	 * @return 是数字为true
	 */
	private  boolean isNum(int pos){
		if (pos<0 || pos>=fileNameL.length()) return false;
		return Character.isDigit(fileNameL.charAt(pos));
		
	}
	/**
	 * 判断此单词是否为“纯英文单词”
	 * 条件：此字串中的每一个字符都是数字或字母
	 * 如"2ab","1","a1","abc"是true
	 * @param word  此单词的字符串
	 * @return
	 */
	private static boolean isPureEn(String word){
		int i;
		for (i=0;i<word.length();i++) 
			if (!isEnLetterOrDigit(word.charAt(i))) return false;
		return true;
		
	}
	/**
	 * 是否为[a-z][A-Z][0-9][,][-][_]['][~]中的元素
	 * @param ch
	 * @return
	 */
	private static boolean isEnLetterOrDigit(char ch){
		if (ch>='a' && ch <='z') return true;
		if (ch>='A' && ch <='Z') return true;
		if (ch>='0' && ch <='9') return true;
		if (ch=='\'' || ch==',' || ch=='_' || ch=='-'|| ch=='~') return true;
		return false;
	}
	 
	private static void loadData(){
		List<String> ss=FileSystemUtil.readEveryLineOfFile(PropertyReader.getWikiNameInfoFile());
		if (ss==null) {
			System.out.println("WikiNameInfoParser:load Data failure.");
			return;
		}
		int i=-1,part=-1;//当前部分所属的标签的tagId
		String s;	//当前行
		while (++i<ss.size()){
			s=ss.get(i).trim();
			//空行和注释行直接跳过
			if ("".equals(s)) continue;
			if (s.startsWith("#")) continue;
			if (s.startsWith("[") && s.endsWith("]"))
				//包含方括号的这一行表示是一个新的标签部分
				part=getTagId(s.substring(1,s.length()-1));
			else {
				//此行是一行关键字
				String[] keys=s.split(",");
				
				//第1个关键字是所要显示的名称
				String val=keys[0].trim();
				for (String key:keys) put(key.trim().toLowerCase(),trimDots(val),part);
			}
			
			
		}
		isDataLoaded=true;
	}
	
	/**
	 * 去方括号,找']'时，以最左边的为准
	 * 如： "[eee][re]r" 返回"eee"
	 * @param arg
	 * @return
	 */
	private static String trimBrackets(String arg){
		int len=arg.length();
		if (len>1){
			int a1=(arg.charAt(0)=='[')? 1:0;
			int a2=arg.indexOf(']');
			if (a2<0 || a2<a1) a2=len;
			return arg.substring(a1,a2);
		}
		return arg;
	}
	/**
	 * 去两边的小圆点
	 * 如".ffg.rer." 返回"ffg.rer"
	 * @param arg
	 * @return
	 */
	private static String trimDots(String arg){
		int len=arg.length();
		if (len>1){
			int a1=(arg.charAt(0)=='.')? 1:0;
			int a2=(arg.charAt(len-1)=='.')? len-1:len;
			return arg.substring(a1,a2);
		}
		return arg;
	}
	private static int getTagId(String tag){
		if ("sources".equalsIgnoreCase(tag)) return 1;
		if ("versions".equalsIgnoreCase(tag)) return 2;
		if ("standards".equalsIgnoreCase(tag)) return 3;
		if ("organizations".equalsIgnoreCase(tag)) return 4;	
		if ("producers".equalsIgnoreCase(tag)) return 4;	
		return -1;
	}
	
	private static void put(String key,String val,int tagId){
		switch(tagId){
		case -1: break;
		case 1: mSources.put(key,val);break;
		case 2: mVersions.put(key,val);break;
		case 3: mStandards.put(key,val);break;
		case 4: mProducers.put(key,val);break;
		}
	}
	
	
	
	public String getFileName() {
		return fileNameL;
	}

	public void setFileName(String fileName) {
		this.fileNameL = fileName;
	}

	public String getEnglishName() {
		return EnglishName;
	}

	public String getAsianName() {
		return AsianName;
	}

	public String getYear() {
		return year;
	}

	public String getSource() {
		return source;
	}

	public String getVersion() {
		return version;
	}

	public String getProducer() {
		return producer;
	}

	public String getStandard() {
		return standard;
	}
	
	
	
	
}
